package cn.cdeden.knowledge.service.impl;

import cn.cdeden.common.core.utils.MapstructUtils;
import cn.cdeden.common.core.utils.page.TableDataInfo;
import cn.cdeden.common.mybatis.validator.QueryHelpMybatisPlus;
import cn.cdeden.common.satoken.utils.LoginHelper;
import cn.cdeden.knowledge.domain.EnterpriseFilesTree;
import cn.cdeden.knowledge.domain.PersonalFilesTree;
import cn.cdeden.knowledge.domain.TeamFilesTree;
import cn.cdeden.knowledge.domain.dto.*;
import cn.cdeden.knowledge.domain.vo.FilesLabelRecordVo;
import cn.cdeden.knowledge.enums.FileLabelTypeEnums;
import cn.cdeden.knowledge.enums.TreeEnum;
import cn.cdeden.knowledge.mapper.FilesLabelMapper;
import cn.cdeden.knowledge.mapper.FilesLabelRecordMapper;
import cn.cdeden.knowledge.service.*;
import cn.cdeden.knowledge.utils.CollectionUtilsImpl;
import cn.cdeden.knowledge.utils.PageUtil;
import cn.cdeden.system.api.model.LoginUser;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.AllArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.cdeden.knowledge.domain.FilesLabelRecord;
import org.springframework.transaction.annotation.Transactional;

@Service
@AllArgsConstructor
public class FilesLabelRecordServiceImpl extends ServiceImpl<FilesLabelRecordMapper, FilesLabelRecord> implements FilesLabelRecordService {

    // private final RedisUtils redisUtils;
    private final FilesLabelRecordMapper filesLabelRecordMapper;

    //文件
    private final FileService filePersonalService;
    private final TeamFilesTreeService teamFilesTreeService;
    private final EnterpriseFilesTreeService enterpriseTreeService;

    private final FilesLabelService filesUserLabelService;

    private final FilesLabelMapper labelMapper;

//    private Executor executor = (Executor) GetBeanUtil.getBean("taskQueueThreadPool");


    @Override
    public TableDataInfo<FilesTree> queryAll(FilesLabelRecordQueryParam query, Pageable pageable) {
        LoginUser user = LoginHelper.getLoginUser();
        String username = user.getUsername();
        String userId = Long.toString(user.getUserId());
        QueryWrapper<FilesLabelRecord> predicate = QueryHelpMybatisPlus.getPredicate(query);
        if (StringUtils.isBlank(query.getLabelType())) {
            predicate.eq("create_Id", userId);
        } else {

        }


        List<FilesLabelRecord> filesLabelRecords = filesLabelRecordMapper.selectList(predicate);
        if (CollectionUtils.isNotEmpty(filesLabelRecords)) {
            List<Long> collect = filesLabelRecords.stream().map(FilesLabelRecord::getFileId).collect(Collectors.toList());
            ///查询个人 树 团队树 ,团队树数据,企业的
            TableDataInfo<FilesTree> filesTree = getFilesTree(query.getFileType(), collect, query.getLabelName(), userId, pageable);

            return filesTree;
        }
        return TableDataInfo.build();
    }

    @Override
    public TableDataInfo<FilesTree> queryFileInfo(FilesLabelRecordQueryParam query, Pageable pageable) {
        return null;
    }

    @Override
    public List<FilesTree> querySys(FilesLabelRecordQueryParam query) {
        LoginUser user = LoginHelper.getLoginUser();
//        FileUserDto user = FileUserUtils.getUser(); //用户信息

        String userId = Long.toString(user.getUserId());

        QueryWrapper<FilesLabelRecord> predicate = QueryHelpMybatisPlus.getPredicate(query);
        List<FilesLabelRecord> records = filesLabelRecordMapper.selectList(predicate);

        ///查询个人 树 团队树 ,团队树数据,企业的
        List<FilesTree> filesTree = getFilesTreeAll(records, userId);
        return filesTree;
    }


    @Override
    public List<FilesLabelRecordVo> querySelect(FilesLabelRecordQueryParam query) {
        LoginUser user = LoginHelper.getLoginUser();
//        FileUserDto user = FileUserUtils.getUser(); //用户信息
        String username = user.getUsername();
        String teamId = query.getTeamId();
        String userId = Long.toString(user.getUserId());
        FileLabelTypeEnums enums = FileLabelTypeEnums.find(query.getLabelType());
        if (enums != null) {
            switch (enums) {
                case team:
                    if (StringUtils.isBlank(teamId)) throw new RuntimeException("缺失团队编号");
                case sys:
                    userId = null;
                case user:
                    break;
                default:
                    throw new RuntimeException("错误的标签的类型");
            }
        } else {
            throw new RuntimeException("错误的标签的类型");
        }

        List<FilesLabelRecordVo> recordVos = filesLabelRecordMapper.querySelect(userId,
            query.getFileType(),
            query.getFileId(),
            query.getLabelId(),
            enums.getCode(),
            teamId
        );
        return recordVos;
    }

    @Override
    public TableDataInfo<FilesLabelRecordVo> querySelectPage(FilesLabelRecordQueryParam query, Pageable pageable) {
        LoginUser user = LoginHelper.getLoginUser();
//        FileUserDto user = FileUserUtils.getUser(); //用户信息
        String userId = Long.toString(user.getUserId());
        String teamId = query.getTeamId();
        FileLabelTypeEnums enums = FileLabelTypeEnums.find(query.getLabelType());
        if (enums != null) {
            switch (enums) { //添加不同的查询方式
                case team:
                    if (StringUtils.isBlank(teamId)) throw new RuntimeException("缺失团队编号");
                case sys:
                    userId = null;
                case user:
                    break;
                default:
                    throw new RuntimeException("错误的标签的类型");
            }
        } else {
            throw new RuntimeException("错误的标签的类型");
        }

        IPage<FilesLabelRecordVo> page = filesLabelRecordMapper.querySelect(
            userId,
            query.getFileType(),
            query.getFileId(),
            query.getLabelId(),
            enums.getCode(),
            teamId,
            new Page<>(pageable.getPageNumber(), pageable.getPageSize()));
        return TableDataInfo.build(page);
    }


    private TableDataInfo<FilesTree> getFilesTree(String fileType, List<Long> fileIds, String fileName, String userId, Pageable pageable) {

        TreeEnum treeEnum = TreeEnum.find(fileType);
        List<String> fileIds01 = fileIds.stream().map(aLong -> String.valueOf(aLong)).collect(Collectors.toList());
        if (treeEnum != null) {
            switch (treeEnum) {
                case PERSONAL:
                    //个人
                    return MapstructUtils.convertTableDataInfo(TableDataInfo.build(filePersonalService.selectFilesTree(fileIds01, fileName, pageable)), FilesTree.class);
                case TEAM:
                    //团队
//                    List<FilesTree> teamTrees = teamFilesTreeService.queryAll();
                    List<FilesTree> trees = teamFilesTreeService.selectFilesTree(fileIds01);
                    if (trees == null) return null;
                    Set<Long> collect = trees.stream().map(FilesTree::getId).collect(Collectors.toSet());
                    IPage<TeamFilesTree> iPageTeam = PageUtil.toMybatisPage(pageable);
                    IPage<TeamFilesTree> pageTeam = teamFilesTreeService.lambdaQuery()
                        .in(TeamFilesTree::getId, collect)
                        .isNull(TeamFilesTree::getDeleteId)
                        .like(StringUtils.isNotBlank(fileName), TeamFilesTree::getRealName, fileName)
                        .page(iPageTeam);
                    ;
                    TableDataInfo<FilesTree> teamFilesTreeDtoTableDataInfo = MapstructUtils.convertTableDataInfo(TableDataInfo.build(pageTeam), FilesTree.class);
//                    IPage<FilesTree> filesTreeIPage = MapstructUtils.convert(MapstructUtils.convert(pageTeam, TeamFilesTreeDto.class), FilesTree.class);

                    teamFilesTreeDtoTableDataInfo.getRows().forEach(filesTree -> filesTree.setTeamName(filesTree.getTeamId()));
                    return teamFilesTreeDtoTableDataInfo;
                case ENTERPRISE:
                    List<FilesTree> list = enterpriseTreeService.selectFilesTree(fileIds01, userId);
                    if (list == null) return null;
                    Set<Long> ids = list.stream().map(FilesTree::getId).collect(Collectors.toSet());
                    IPage<EnterpriseFilesTree> iPage = PageUtil.toMybatisPage(pageable);
                    IPage<EnterpriseFilesTree> page = enterpriseTreeService.lambdaQuery()
                        .in(EnterpriseFilesTree::getId, ids)
                        .isNull(EnterpriseFilesTree::getDeleteId)
                        .like(StringUtils.isNotBlank(fileName), EnterpriseFilesTree::getRealName, fileName)
                        .page(iPage);

                    TableDataInfo<EnterpriseFilesTree> build = TableDataInfo.build(page);
                    TableDataInfo<EnterpriseFilesTreeDto> enterpriseFilesTreeDtoTableDataInfo = MapstructUtils.convertTableDataInfo(build, EnterpriseFilesTreeDto.class);
                    return MapstructUtils.convertTableDataInfo(enterpriseFilesTreeDtoTableDataInfo, FilesTree.class);
            }
        }
        return null;
    }


    private List<FilesTree> getFilesTreeAll(List<FilesLabelRecord> records, String userId) {
        Set<String> personalIds = new HashSet<>();
        Set<String> teamIds = new HashSet<>();
        Set<String> enterpriseIds = new HashSet<>();
        records.forEach(recordList -> {
            String fileType = recordList.getFileType();
            if (StringUtils.equalsIgnoreCase(fileType, TreeEnum.PERSONAL.getType())) {
                //个人
                personalIds.add(String.valueOf(recordList.getFileId()));
            } else if (StringUtils.equalsIgnoreCase(fileType, TreeEnum.TEAM.getType())) {
                //团队
                teamIds.add(String.valueOf(recordList.getFileId()));
            } else if (StringUtils.equalsIgnoreCase(fileType, TreeEnum.ENTERPRISE.getType())) {
                //企业
                enterpriseIds.add(String.valueOf(recordList.getFileId()));
            }
        });
        List<FilesTree> filesTrees = new ArrayList<>();

//        用线程去查询
        //查找树
        CompletableFuture<List<FilesTree>> personalTask = ExecutorThreadPool(personalIds, TreeEnum.PERSONAL.getType(), userId);
        CompletableFuture<List<FilesTree>> teamTask = ExecutorThreadPool(teamIds, TreeEnum.TEAM.getType(), userId);
        CompletableFuture<List<FilesTree>> enterpriseTask = ExecutorThreadPool(enterpriseIds, TreeEnum.ENTERPRISE.getType(), userId);
        try {
            List<FilesTree> personalTrees = personalTask.get();
            List<FilesTree> teamTrees = teamTask.get();
            List<FilesTree> enterpriseTrees = enterpriseTask.get();
            boolean b1 = CollectionUtils.isNotEmpty(personalTrees) ? filesTrees.addAll(personalTrees) : false;
            boolean b2 = CollectionUtils.isNotEmpty(teamTrees) ? filesTrees.addAll(teamTrees) : false;
            boolean b3 = CollectionUtils.isNotEmpty(enterpriseTrees) ? filesTrees.addAll(enterpriseTrees) : false;
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }

        if (CollectionUtils.isNotEmpty(filesTrees)) {
            //排序返回
//            排序
            List<FilesTree> files = new ArrayList<>();

            records.forEach(file -> {
                for (int i = filesTrees.size() - 1; i >= 0; i--) {
                    FilesTree tree = filesTrees.get(i);
                    if (StringUtils.equals(file.getFileType(), tree.getLibraryType())
                        && StringUtils.equals(String.valueOf(file.getFileId()), String.valueOf(tree.getId()))
                    ) {
                        tree.setLabelId(String.valueOf(file.getLabelId()));
                        files.add(tree);
                        filesTrees.remove(i);
                    }
                }
            });
            return files;
        }
        return null;

    }

    /**
     * @param ids
     * @param fileType
     * @param userId   用户编号
     * @return java.util.concurrent.CompletableFuture
     * @author Yu.
     * @Description // 线程池的获取数据
     * @Date 2022/10/26 14:49
     **/
    public CompletableFuture<List<FilesTree>> ExecutorThreadPool(Collection<String> ids, String fileType, String userId) {
        CompletableFuture<List<FilesTree>> task = CompletableFuture.supplyAsync(() -> {
            if (CollectionUtils.isEmpty(ids)) {
                return null;
            }
            if (StringUtils.equalsIgnoreCase(fileType, TreeEnum.PERSONAL.getType())) {
                //个人
                return null;
//                return filePersonalService.selectFilesTree(ids);
//            }else if (StringUtils.equalsIgnoreCase(fileType,TreeEnum.TEAM.getType())){
//                //团队
//                List<FilesTree> trees = teamFilesTreeService.selectFilesTree(ids);
//                if (trees==null) return trees;
//                for (FilesTree tree : trees) {
//                    tree.setTeamName(String.valueOf(tree.getTeamId()));
//                }
//                return trees;
            } else if (StringUtils.equalsIgnoreCase(fileType, TreeEnum.ENTERPRISE.getType())) {
                //企业
                return enterpriseTreeService.selectFilesTree(ids, userId);
            }
            return null;
        });
        return task;
    }


    @Override
    public List<FilesLabelRecordDto> queryAll(FilesLabelRecordQueryParam query) {
        return MapstructUtils.convert(filesLabelRecordMapper.selectList(QueryHelpMybatisPlus.getPredicate(query)), FilesLabelRecordDto.class);
    }


    @Override
    public FilesLabelRecord getById(Long id) {
        return filesLabelRecordMapper.selectById(id);
    }

    @Override
    // @Cacheable(key = "'id:' + #p0")
    public FilesLabelRecordDto findById(Long id) {
        return MapstructUtils.convert(getById(id), FilesLabelRecordDto.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean insert(FilesLabelRecordList resources) {
        LoginUser user = LoginHelper.getLoginUser();
//        FileUserDto user = FileUserUtils.getUser(); //用户信息
        String username = user.getUsername();
        String userId = Long.toString(user.getUserId());
        List<String> ids = resources.getLabelId();
        Long fileId = resources.getFileId();//文件树id
        String fileType = resources.getFileType(); //文件类型
        String labelType = resources.getLabelType(); //那个库的类型
        String teamId = resources.getTeamId();


        List<FilesLabelRecord> list = filesLabelRecordMapper.selectList(
            new LambdaQueryWrapper<FilesLabelRecord>()
                .in(FilesLabelRecord::getLabelId, ids)
                .eq(FilesLabelRecord::getFileId, fileId)
                .eq(FilesLabelRecord::getFileType, fileType)
        );

        if (CollectionUtils.isNotEmpty(list)) {
            List<String> longs = list.stream().map(FilesLabelRecord::getLabelId).map(String::valueOf).collect(Collectors.toList());
            Map<String, List<String>> listMap = CollectionUtilsImpl.compare(longs, ids);
            ids = listMap.get(CollectionUtilsImpl.ADD_LIST);
        }


        List<FilesLabelRecord> records = new ArrayList<>();
        ids.forEach(labelId -> {
            FilesLabelRecord record = new FilesLabelRecord();
            record.setLabelId(Long.valueOf(labelId));
            record.setFileType(fileType);
            record.setFileId(fileId);
            record.setCreateId(userId);
            record.setCreateBy(username);
            if (StringUtils.isNotBlank(teamId)) record.setTeamId(teamId);
            record.setCreateTime(new Date());
            records.add(record);
        });
        return this.saveBatch(records);
    }

    @Override
    @Transactional
    public boolean insertFileList(FilesLabelRecordFileList resources) {
        LoginUser user = LoginHelper.getLoginUser();
//        FileUserDto user = FileUserUtils.getUser(); //用户信息
        String username = user.getUsername();
        String userId = Long.toString(user.getUserId());
        List<String> ids = resources.getLabelId();
//        Long fileId = resources.getFileId();//文件树id
        List<String> fileIds = resources.getFileIds();
        String fileType = resources.getFileType(); //文件类型
        String labelType = resources.getLabelType(); //那个库的类型
        String teamId = resources.getTeamId();
//        LambdaQueryWrapper<FilesLabelRecord> wrapper = new LambdaQueryWrapper<>();
        LambdaQueryChainWrapper<FilesLabelRecord> wrapper = this.lambdaQuery();
        for (String fileId : fileIds) {
            wrapper.or(e -> {
                e.in(FilesLabelRecord::getLabelId, ids)
                    .eq(FilesLabelRecord::getFileId, fileId)
                    .eq(FilesLabelRecord::getFileType, fileType);
            });
        }
        List<FilesLabelRecord> list = wrapper.list();
        if (CollectionUtils.isNotEmpty(list)) {
            List<Long> longs = list.stream().map(FilesLabelRecord::getId).collect(Collectors.toList());
            this.removeByIds(longs);
        }


        List<FilesLabelRecord> records = new ArrayList<>();
        for (String fileId : fileIds) {
            ids.forEach(labelId -> {
                FilesLabelRecord record = new FilesLabelRecord();
                record.setLabelId(Long.valueOf(labelId));
                record.setFileType(fileType);
                record.setFileId(Long.valueOf(fileId));
                record.setCreateId(userId);
                record.setCreateBy(username);
                if (StringUtils.isNotBlank(teamId)) record.setTeamId(teamId);
                record.setCreateTime(new Date());
                records.add(record);
            });
        }


        return this.saveBatch(records);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(FilesLabelRecordDto resources) {
        FilesLabelRecord entity = MapstructUtils.convert(resources, FilesLabelRecord.class);
        boolean b = this.updateById(entity);
        // delCaches(resources.id);
        return b;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteByIds(Set<Long> ids) {
        // delCaches(ids);
        return this.removeByIds(ids);
    }

    @Override
    public boolean deleteByLabelIds(Set<Long> ids) {
        QueryWrapper<FilesLabelRecord> wrapper = new QueryWrapper<>();
        wrapper.in("label_id", ids);
        return this.remove(wrapper);
    }

    @Override
    public boolean deleteByFileIds(Collection<String> ids, String type) {
        QueryWrapper<FilesLabelRecord> wrapper = new QueryWrapper<>();
        wrapper.in("file_id", ids)
            .eq("file_type", type)
        ;
        return this.remove(wrapper);
    }

    @Override
    public boolean deleteByLabelFileIds(Collection<String> ids, String type, Long fileId) {
        QueryWrapper<FilesLabelRecord> wrapper = new QueryWrapper<>();
        wrapper.in("label_id", ids)
            .eq("file_type", type)
            .eq("file_id", fileId)
        ;
        return this.remove(wrapper);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteById(Long id) {
        Set<Long> set = new HashSet<>(1);
        set.add(id);
        return this.deleteByIds(set);
    }
}
